
package com.springcloud.sc.ucpv5.client.application.message;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import com.springcloud.sc.ucpv5.client.application.message.connect.ConnectFather;
import com.springcloud.sc.ucpv5.client.application.message.connect.TcpConnect;
import com.springcloud.sc.ucpv5.client.application.message.connect.TcpProBufConnect;
import com.springcloud.sc.ucpv5.client.application.message.connect.VtcpConnect;
import com.springcloud.sc.ucpv5.client.application.util.FrameworkUtil;
import com.springcloud.sc.ucpv5.client.common.CmdDefine;
import com.springcloud.sc.ucpv5.client.commondata.SecuResult;
import com.springcloud.sc.ucpv5.client.commondata.data.MsgHeader;
import com.springcloud.sc.ucpv5.client.commondata.datachange.DataExChange;
import com.springcloud.sc.ucpv5.client.module.datamanager.BaseDataManager;
import com.springcloud.sc.ucpv5.client.module.datamanager.LoginDataManager;
import com.springcloud.sc.ucpv5.client.module.setting.SettingManager;
import com.springcloud.sc.ucpv5.client.util.PublicUtil;
import com.springcloud.sc.ucpv5.client.util.PublicUtil.DispatchRunnable;



public class MessageService {
    public static String userName = "";

    protected String version_change_value_current = "DCS_UCP_FOR_IDL_V3.0";

    protected HashMap<Integer, SyncMsgResult> syncResultHm = new HashMap<Integer, SyncMsgResult>();

	public final static int ERROR_CODE_TIME_OUT = 6020;// 操作超时

	public final static int ERROR_CODE_TRANSFER_FAIL = 6021;// 通信失败

	public final static int ERROR_CODE_SOCKET_SHUTDOWN = 6022;

	public final static int ERROR_CODE_CONNECT_FAIL = 6023;

	public final static int ERROR_CODE_SEND_MSG_NULL = 6024;

	public final static int ERROR_CODE_WRITE_SOCKET_FAIL = 6025;

	public final static int ERROR_CODE_HLR_DISCONNECT = 6026;

	public final static int ERROR_CODE_SXC_DISCONNECT = 6027;

	public final static int ERROR_CODE_NOT_REGISTER = 6028;

	public final static int ERROR_CODE_OFFLINE_DATA = 6029;

	// 解码失败,可能版本引起的
	public final static int ERROR_CODE_ENCODE_FAIL = 6030;// 通信失败

	public final static int ERROR_CODE_SESSION_ERROR = 10012;

	final static int ERROR_CODE_SESSION_MAX_LIMIT = 6002;// 登录用户到达最大值

	final static int DEFAULT_TIME_OUT = 60 * 1000;

	// 请求ID,同步的时候要填写
	int requestID = 0;

	/**
	 * 当前登录IP和port
	 */
	private String currentIP = "";

	private int currentPort = 0;


	protected String physicsNodeNumber = "";
	protected String logicNodeNumber = "";

    protected ConnectFather messageConnect = null;

	private static class MessageManagerLoader {
		private static final MessageService instance = new MessageService();
	}

	public static MessageService getInstance() {
		return MessageManagerLoader.instance;
	}


	public MessageService() {
		version_change_value_current = SettingManager.SYS.DefaultVersionFlag();

	if (SettingManager.SYS.ServerVerType_V4_Old()){
	    messageConnect = new TcpConnect();
	}
	else if (SettingManager.SYS.ServerVerType_V4()) {
	    messageConnect = new VtcpConnect();
	} else if (SettingManager.SYS.ServerVerType_V5()) {
	    messageConnect = new TcpProBufConnect();
	}

		doDataFromServerThread = new Thread() {
			public void run() {
				// 收包循环
				while (true) {
					try {
						// 转换, 并发送内部处理
						if (msgQueueFromServer.isEmpty()) {
							Thread.sleep(1);
						} else {
							doDataFromServer(msgQueueFromServer.poll());
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		doDataFromServerThread.start();
	}

	private Thread doDataFromServerThread = null;
	protected BlockingQueue<MsgHeader> msgQueueFromServer = new ArrayBlockingQueue<MsgHeader>(10000);

	public void doDataFromServer(MsgHeader message) {
		try {
			try {
				int errCode = MesssageHandle.getInstance().handleMessage(message);
				if (errCode != 0) {
					// 根据返回的错误码获取错误信息
				}

			} catch (Throwable e) {
				// You might want to log something here
				e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String localeIp = "";

	public String getLocalIp() {
		return localeIp;
	}

	public void setLocalIP(String ip) {
		this.localeIp = ip;
	}

	/**
	 * 初始化连接
	 * 
	 * 
	 */
	public int init(final String strServerIP, final int iServerPort) throws MessageServiceException {
		currentIP = strServerIP;
		currentPort = iServerPort;

		Integer retInt = (Integer) PublicUtil.syncExec(new DispatchRunnable() {
			public Object run() {
				int retCode = -1;
				try {
					retCode = messageConnect.internalInit(strServerIP, iServerPort, false);
					try {
						Thread.sleep(1000);

					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} catch (MessageServiceException e) {
					e.printStackTrace();
				}
				return new Integer(retCode);
			}

			public boolean isInterrupted() {
				return false;
			}

		}, 30 * 3 * 1000);
		if (null == retInt) {
			return -1;
		} else {
			return retInt.intValue();
		}
	}

	public boolean reconnect() {
		if (true) {
			try {
				int ret = messageConnect.internalInit(this.currentIP, this.currentPort, true);
				if (ret == 0) {
					SecuResult result = new SecuResult();
					DataMessageManager.getInstance().LoginSystem(LoginDataManager.getInstance().getName(), LoginDataManager.getInstance().getPassWord(), result, false, false);
					return result.getRetCode() == 0;
				}
				return ret == 0;
			} catch (MessageServiceException e) {
				e.printStackTrace();
			}
			return false;// 调度台不做重连，因为没有办法判断是否已登录
		} else
			return true;
	}

	/**
	 * 检查握手线程
	 */
	public void shakeHandCheck() {
		messageConnect.checkShakeHand();
	}

	/**
	 * 获得下一个请求ID，一般在发送命令时调用.
	 * 
	 * @return int 请求ID
	 */
	public int getRequestID() {
		requestID++;
		if (requestID >= Integer.MAX_VALUE - 1) {
			requestID = 1;
		}
		return requestID;
	}

	/**
	 * 
	 * @date 2006-8-4
	 * @return
	 * @see
	 */
	public int dispose() {
		try {
			Thread.sleep(500);
		} catch (Throwable e) {
		}
		physicsNodeNumber = "";
		logicNodeNumber = "";
		PublicUtil.syncExec(new DispatchRunnable() {
			public Object run() {
				if (isSessionValid()) {
					messageConnect.close();
				}
				return null;
			}

			public boolean isInterrupted() {
				return false;
			}

		}, DEFAULT_TIME_OUT, false);
		// messageConnect.close();
		synchronized (syncResultHm) {
			for (Integer key : syncResultHm.keySet()) {
				syncResultHm.get(key).notifyResult(null);
			}
			syncResultHm.clear();
		}
		// shakeHand = null;
		// clearAsyRegister();
		// updateUiTitle(true);

		return 0;
	}

	public MsgHeader getMessageHeader(int ModuleID, int CmdID) {
		return getMessageHeader(ModuleID, CmdID, null, null);
	}

	/**
     * 
     * 
     */
	public MsgHeader getMessageHeader(int ModuleID, int CmdID, String physicsNodeNumber, String logicNodeNumber) {
		MsgHeader accMsgHeader = new MsgHeader();
		accMsgHeader.SessionID = messageConnect.getSessionId();
		accMsgHeader.TranceID = 0;
		accMsgHeader.ModuleID = ModuleID;

		accMsgHeader.CmdID = CmdID;
		if (physicsNodeNumber == null || physicsNodeNumber.equals(this.physicsNodeNumber) || this.physicsNodeNumber.equals("")) {
			accMsgHeader.Physics_NodeNumber = ""; // 本节点消息用空串表示
		} else {
			accMsgHeader.Physics_NodeNumber = physicsNodeNumber;
		}
		accMsgHeader.NodeNumber = logicNodeNumber == null ? this.logicNodeNumber : logicNodeNumber;

		accMsgHeader.SrcNodeNumber = getLogicNodeNumber();
		accMsgHeader.SrcPhysics_NodeNumber = getPhysicsNodeNumber();

		accMsgHeader.Result = 0;
		accMsgHeader.Flag = 1;
		accMsgHeader.CmdIDFlag = 0; // 请求：0; 响应：1
		accMsgHeader.Keep2 = "";
		accMsgHeader.Keep3 = version_change_value_current;

		accMsgHeader.MsgContent = new byte[0];

		if (!accMsgHeader.Physics_NodeNumber.equals("")) {
			// System.out.println("异步节点出现啦.................................this.physicsNodeNumber"
			// + this.physicsNodeNumber + " physicsNodeNumber:" +
			// physicsNodeNumber);
		}

		return accMsgHeader;
	}

	/**
     * 
     * 
     */
	public void putMessage(MsgHeader header) {
		FrameworkUtil.trace("Recieve:", header.TranceID, header);
		if (header.CmdID == CmdDefine.CMD_User_Login || header.CmdID == CmdDefine.CMD_User_Login_regcheck || header.CmdID == CmdDefine.CMD_User_Login_md5_check) { // 如果登录消息响应用的话，把相关信息记录起来
			this.physicsNodeNumber = header.Physics_NodeNumber;
			this.logicNodeNumber = header.NodeNumber.equals("") ? header.Physics_NodeNumber : header.NodeNumber;

			// 0530 设置当前节点的节点号码
			BaseDataManager.getInstance().initLoginNode(physicsNodeNumber, logicNodeNumber);

		}

		if (header.TranceID > 0) { // 同步消息处理
			synchronized (syncResultHm) {
				SyncMsgResult result = syncResultHm.get(header.TranceID);
				if (result != null) {
					result.notifyResult(header);
				} else {
					// 打印 当期sessonId 和 当前登录端口
					StringBuffer buffer = new StringBuffer();
					PublicUtil.debugInfo(buffer.toString());
				}
			}
			return;
		}
		try {
			// 通知线程处理消息分发
			msgQueueFromServer.put(header);
		} catch (Exception e) {
			e.printStackTrace(System.err);
		}
	}

	private String getMsgHeaderKey(MsgHeader header) {
		return header.CmdID + "";
	}

	public boolean isSessionValid() {
		return messageConnect.checkConnectOk();
	}

	public void setSessionValid(boolean b) {
		if (!b)
			try {
				messageConnect.setConnnectClose();
			} catch (Exception exp) {
				;
			}
	}

	public String getCurrentIP() {
		return currentIP;
	}

	public int getCurrentPort() {
		return currentPort;
	}

	public class SyncMsgResult {
		ArrayList<MsgHeader> resultList = new ArrayList<MsgHeader>();
		int retCode;

		void waitResult(int timeout) {
			synchronized (this) {
				try {
					this.wait(timeout * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		void notifyResult(MsgHeader result) {
			if (result == null)
				return;
			synchronized (this) {
				resultList.add(result);
				if (result.Flag == 1) {
					retCode = "1".equals(result.Keep2) ? ERROR_CODE_OFFLINE_DATA : 0;// 离线数据
					syncResultHm.remove(result.TranceID);
					this.notifyAll();
				}
			}
		}
	}

	public String getPhysicsNodeNumber() {
		return physicsNodeNumber;
	}

	public String getLogicNodeNumber() {
		return logicNodeNumber;
	}

	/**
	 * 判断是否与当前节点一样属于同一个物理节点
	 * 
	 * @param physicsNodeNumber
	 * @return
	 */
	public boolean isLocalNodeData(String physicsNodeNumber) {
		if (physicsNodeNumber == null || physicsNodeNumber.equals(this.physicsNodeNumber)) {
			return true; // 本节点消息用空串表示
		}

		return false;
	}

	public boolean isLocalPortRight() {
		// return ConnectUtil.getInstance().isLocalPortRight();
		return true;
	}

	public boolean testTcpAviable(String strServerIP, final int iServerPort, int timeout) {
		// return ConnectUtil.getInstance().testTcpAviable(strServerIP,
		// iServerPort, timeout);

		return true;
	}

	/** probuf begin ***/

	public int sendSyncMsg(MsgHeader header, DataExChange message, DataExChange report) {
		return sendSyncMsg(header, message, report, true, 60 * 1000);
	}

	/**
	 * 发送同步消息
	 * 
	 * @param header
	 *            发送命令的消息头，通过getMessageHeader获取;
	 * @param message
	 *            命令参数;
	 * @param report
	 *            后台返回的通用的报告;
	 * @return 0表示成功，通信错误返回错误码在 com.idx.cnms.client.framework.util.ErrCode 中定义.
	 */
	public int sendSyncMsg(final MsgHeader header, final DataExChange message, final DataExChange report, final boolean isAutoBusy, final int timeout) {
		try {
			if (!isSessionValid()) {
				return ERROR_CODE_SOCKET_SHUTDOWN;// 6000==通信失败
			}
			header.TranceID = getRequestID();
			FrameworkUtil.trace("BSendSync:", 0, header);
			int timeOut = timeout + 2000;
			Integer retInt = (Integer) PublicUtil.syncExec(new DispatchRunnable() {
				public Object run() {
					int retCode = internalSendSyncMsg(header, message, report, timeout);
					return new Integer(retCode);
				}

				public boolean isInterrupted() {
					return !isSessionValid();
				}

			}, timeOut, false);

			if (null == retInt) {
				FrameworkUtil.trace("ESendSync [Time out] :", 0, header);
				return ERROR_CODE_TIME_OUT;// 操作超时
			} else {
				FrameworkUtil.trace("ESendSync [" + retInt.intValue() + "] :", 0, header);
				if (-1 == retInt.intValue()) {
					return ERROR_CODE_TRANSFER_FAIL;// 6000==通信失败
				} else {
					return retInt.intValue();
				}
			}
		} finally {
		}
	}

	/**
	 * 发送同步消息
	 * 
	 * @param header
	 *            发送命令的消息头，通过getMessageHeader获取;
	 * @param message
	 *            命令参数;
	 * @param report
	 *            后台返回的通用的报告;
	 * @return 0表示成功，通信错误返回错误码在 com.idx.cnms.client.framework.util.ErrCode 中定义.
	 */
	protected int internalSendSyncMsg(MsgHeader header, DataExChange messageReq, DataExChange report, int timeout) {

		SyncMsgResult msgResult = new SyncMsgResult();
		synchronized (syncResultHm) {
			syncResultHm.put(header.TranceID, msgResult);
		}

		header.Result = messageConnect.writeByteMsg(header, messageReq);

		// FrameworkUtil.trace(header, false);
		if (header.Result != 0) {
			synchronized (syncResultHm) {
				syncResultHm.remove(header.TranceID);
			}
			return ERROR_CODE_TRANSFER_FAIL;
		}

		msgResult.waitResult(timeout);

		synchronized (syncResultHm) {
			syncResultHm.remove(header.TranceID);
		}

		if (msgResult.resultList.size() < 1) {
			return ERROR_CODE_TIME_OUT;
		}

		try {
			for (MsgHeader msgHeader : msgResult.resultList) {
				report.dataContentDataToCommon(msgHeader.MsgContent);
			}
			header.Result = 0;
		} catch (Exception e) {
			// TODO: handle exception
		}

		return msgResult.retCode;
	}

	public int sendASyncMsg(final MsgHeader header, DataExChange message) {
		header.TranceID = 0;// 异步消息，不填消息流水号
		try {
			if (!isSessionValid()) {
				FrameworkUtil.trace("BSend [isSessionValid] ", 0, header);
				return ERROR_CODE_SOCKET_SHUTDOWN;// 6000==通信失败
			}

			FrameworkUtil.trace("BSendAsync:", 0, header);

			Integer retInt = internalSendASyncMsg(header, message);

			if (null == retInt) {
				FrameworkUtil.trace("ESendAsync [Time out] :", 0, header);
				return ERROR_CODE_TIME_OUT;// 操作超时
			} else {
				FrameworkUtil.trace("ESendAsync [" + retInt.intValue() + "] :", 0, header);
				if (-1 == retInt.intValue()) {
					return ERROR_CODE_TRANSFER_FAIL;// 6000==通信失败
				} else {
					return retInt.intValue();
				}
			}
		} finally {
		}
	}

	public int internalSendASyncMsg(MsgHeader header, DataExChange messageReq) {
		if (messageReq == null) {
			return ERROR_CODE_SEND_MSG_NULL;
		}
		return messageConnect.writeByteMsg(header, messageReq);
	}
}
